<script setup lang="ts">
import { onMounted, ref, computed } from "vue";
import { ElMessage } from "element-plus";

type Priority = "low" | "medium" | "high";

defineOptions({ name: "Welcome" });

onMounted(() => {
  fetchWeatherByLocation("上海", "上海");
  loadMemos();
});

// --- 天气（心知 · Seniverse） ---
const weatherLoading = ref(false);
const weatherError = ref("");
const locationLabel = ref("");
const isStale = ref(false);
const currentTemp = ref<number | null>(null);
const currentCode = ref<number | null>(null);
const todayHigh = ref<number | null>(null);
const todayLow = ref<number | null>(null);
const todayPrecip = ref<number | null>(null);
const todayRainfall = ref<number | null>(null);
const daily = ref<
  {
    date: string;
    tmax: number;
    tmin: number;
    pop: number;
    rain: number;
    text: string;
  }[]
>([]);

const WEATHER_CACHE_KEY = "weather_cache_v1";
const SENV_KEY = (import.meta as any).env?.VITE_SENV_KEY || "SDsNayvcDPMUlvNBd";

function getCache(label: string) {
  try {
    const all = JSON.parse(localStorage.getItem(WEATHER_CACHE_KEY) || "{}");
    return all[label];
  } catch {
    return null;
  }
}
function setCache(label: string, data: any) {
  try {
    const all = JSON.parse(localStorage.getItem(WEATHER_CACHE_KEY) || "{}");
    all[label] = data;
    localStorage.setItem(WEATHER_CACHE_KEY, JSON.stringify(all));
  } catch {}
}

async function fetchJSONWithTimeout(
  input: string | URL,
  opts: { timeout?: number; init?: RequestInit } = {}
) {
  const { timeout = 8000, init } = opts;
  const ctrl = new AbortController();
  const id = setTimeout(() => ctrl.abort(), timeout);
  try {
    const res = await fetch(input, { ...(init || {}), signal: ctrl.signal });
    return res;
  } finally {
    clearTimeout(id);
  }
}

function codeToEmoji(code?: number | null) {
  if (code == null) return "⛅️";
  const sun = new Set([0, 1]);
  const cloud = new Set([3, 4]);
  const overcast = new Set([9]);
  const rain = new Set([
    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
  ]);
  const snow = new Set([24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]);
  if (sun.has(code)) return "☀️";
  if (cloud.has(code)) return "🌤️";
  if (overcast.has(code)) return "☁️";
  if (rain.has(code)) return "🌧️";
  if (snow.has(code)) return "🌨️";
  return "⛅️";
}

async function fetchWeatherByLocation(location: string, label?: string) {
  const place = label || location;
  try {
    weatherLoading.value = true;
    weatherError.value = "";
    isStale.value = false;
    locationLabel.value = place;

    const base = "https://api.seniverse.com/v3/weather/daily.json";
    const url = `${base}?key=${encodeURIComponent(SENV_KEY)}&location=${encodeURIComponent(location)}&language=zh-Hans&unit=c&start=0&days=7`;

    let resp = await fetchJSONWithTimeout(url, { timeout: 8000 });
    if (!resp.ok) throw new Error("网络错误");

    const data = await resp.json();
    const result = data?.results?.[0];
    if (!result) throw new Error("无结果");

    const first = result.daily?.[0];
    if (first) {
      currentTemp.value = Number(first.high);
      currentCode.value = Number(first.code_day);
      todayHigh.value = Number(first.high);
      todayLow.value = Number(first.low);
      todayPrecip.value = Math.round(Number(first.precip || 0));
      todayRainfall.value = Number(first.rainfall || 0);
    }

    daily.value = (result.daily || []).map((d: any) => ({
      date: d.date,
      tmax: Number(d.high),
      tmin: Number(d.low),
      pop: Math.round(Number(d.precip || 0)),
      rain: Number(d.rainfall || 0),
      text: d.text_day
    }));

    setCache(place, {
      currentTemp: currentTemp.value,
      currentCode: currentCode.value,
      todayHigh: todayHigh.value,
      todayLow: todayLow.value,
      todayPrecip: todayPrecip.value,
      todayRainfall: todayRainfall.value,
      daily: daily.value,
      ts: Date.now()
    });
  } catch (e) {
    weatherError.value = "天气获取失败（网络超时或被阻断）";
    ElMessage.error("天气获取失败（可能网络超时）");
    const cached = getCache(place);
    if (cached) {
      isStale.value = true;
      currentTemp.value = cached.currentTemp;
      currentCode.value = cached.currentCode;
      todayHigh.value = cached.todayHigh;
      todayLow.value = cached.todayLow;
      todayPrecip.value = cached.todayPrecip;
      todayRainfall.value = cached.todayRainfall;
      daily.value = cached.daily || [];
    }
  } finally {
    weatherLoading.value = false;
  }
}

function autoLocate() {
  if (!("geolocation" in navigator)) return;
  navigator.geolocation.getCurrentPosition(
    pos => {
      const { latitude, longitude } = pos.coords;
      const loc = `${latitude.toFixed(4)}:${longitude.toFixed(4)}`;
      fetchWeatherByLocation(loc, "📍 GPS");
    },
    () => {
      weatherError.value = "定位未授权。";
      ElMessage.info("定位未授权。");
    }
  );
}

// --- 备忘录（支持优先级 & 截止时间） ---
interface Memo {
  id: string;
  text: string;
  done: boolean;
  createdAt: number;
  priority: Priority;
  dueAt: number | null;
}
const memos = ref<Memo[]>([]);
const memoText = ref("");
const selectedPriority = ref<Priority>("medium");
const selectedDueAt = ref<Date | null>(null);
const MEMO_KEY = "memos_v1";

function uid() {
  return Math.random().toString(36).slice(2, 10);
}
function loadMemos() {
  try {
    const raw = JSON.parse(localStorage.getItem(MEMO_KEY) || "[]");
    memos.value = (raw as any[]).map((m: any) => ({
      id: m.id,
      text: m.text,
      done: !!m.done,
      createdAt: m.createdAt ?? Date.now(),
      priority: (m.priority as Priority) ?? "medium",
      dueAt: typeof m.dueAt === "number" ? m.dueAt : null
    }));
  } catch {
    memos.value = [];
  }
}
function saveMemos() {
  localStorage.setItem(MEMO_KEY, JSON.stringify(memos.value));
}

function addMemo() {
  const text = memoText.value.trim();
  if (!text) return;
  memos.value.unshift({
    id: uid(),
    text,
    done: false,
    createdAt: Date.now(),
    priority: selectedPriority.value,
    dueAt: selectedDueAt.value ? selectedDueAt.value.getTime() : null
  });
  memoText.value = "";
  // 保留上次选择的优先级体验更好
  selectedDueAt.value = null;
  saveMemos();
  ElMessage.success("已添加");
}

function updatePriority(id: string, p: Priority) {
  const m = memos.value.find(x => x.id === id);
  if (!m) return;
  m.priority = p;
  saveMemos();
}
function updateDue(id: string, d: Date | null) {
  const m = memos.value.find(x => x.id === id);
  if (!m) return;
  m.dueAt = d ? d.getTime() : null;
  saveMemos();
}
function clearDue(id: string) {
  updateDue(id, null);
}

function toggleMemo(id: string) {
  const m = memos.value.find(x => x.id === id);
  if (!m) return;
  m.done = !m.done;
  saveMemos();
}
function removeMemo(id: string) {
  memos.value = memos.value.filter(x => x.id !== id);
  saveMemos();
  ElMessage.info("已删除");
}
function clearCompleted() {
  memos.value = memos.value.filter(x => !x.done);
  saveMemos();
  ElMessage.success("已清除已完成");
}

const priorityMeta: Record<
  Priority,
  { label: string; type: "info" | "warning" | "danger" }
> = {
  low: { label: "低", type: "info" },
  medium: { label: "中", type: "warning" },
  high: { label: "高", type: "danger" }
};
function fmtDue(ts: number | null) {
  if (!ts) return "—";
  const d = new Date(ts);
  return d.toLocaleString("zh-CN", {
    month: "numeric",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit"
  });
}
function dueStatus(m: Memo) {
  if (!m.dueAt || m.done) return "";
  const now = Date.now();
  if (m.dueAt < now) return "overdue";
  if (m.dueAt - now < 24 * 3600 * 1000) return "soon";
  return "";
}
function prioOrder(p: Priority) {
  return p === "high" ? 2 : p === "medium" ? 1 : 0;
}

const memosView = computed(() => {
  return [...memos.value].sort((a, b) => {
    if (a.done !== b.done) return a.done ? 1 : -1;
    if (prioOrder(a.priority) !== prioOrder(b.priority))
      return prioOrder(b.priority) - prioOrder(a.priority);
    if ((a.dueAt ?? Infinity) !== (b.dueAt ?? Infinity))
      return (a.dueAt ?? Infinity) - (b.dueAt ?? Infinity);
    return b.createdAt - a.createdAt;
  });
});
</script>

<template>
  <el-container class="page">
    <el-main>
      <section class="container dashboard">
        <el-row :gutter="16">
          <!-- 左：天气卡片 -->
          <el-col :xs="24" :md="12">
            <el-card shadow="hover" class="block-card weather-card">
              <template #header>
                <div class="block-header">
                  <span class="card-title">天气预报</span>
                  <el-button size="small" @click="autoLocate" round
                    ><i>📍</i> 定位</el-button
                  >
                </div>
              </template>

              <!-- 加载骨架屏 -->
              <template v-if="weatherLoading">
                <el-skeleton :rows="5" animated style="padding: 4px 8px" />
              </template>

              <div v-else class="weather">
                <!-- 顶部主卡片 -->
                <div class="current gradient-card">
                  <div class="current-left">
                    <div class="big">{{ currentTemp ?? "—" }}°</div>
                    <div class="location">
                      <span class="city">{{ locationLabel }}</span>
                      <el-tag
                        v-if="isStale"
                        size="small"
                        effect="plain"
                        type="warning"
                        >离线缓存</el-tag
                      >
                    </div>
                  </div>
                  <div class="current-right">
                    <div class="wx-icon">{{ codeToEmoji(currentCode) }}</div>
                  </div>
                </div>

                <!-- 指标条 -->
                <div class="metrics">
                  <div class="metric">
                    <span class="label">最高</span
                    ><b>{{ todayHigh ?? "—" }}°</b>
                  </div>
                  <div class="metric">
                    <span class="label">最低</span><b>{{ todayLow ?? "—" }}°</b>
                  </div>
                  <div class="metric">
                    <span class="label">降水概率</span
                    ><b>{{ todayPrecip ?? "—" }}%</b>
                  </div>
                  <div class="metric">
                    <span class="label">降雨量</span
                    ><b>{{ todayRainfall ?? "—" }}mm</b>
                  </div>
                </div>

                <!-- 7日预报 -->
                <transition-group name="fade" tag="div" class="forecast">
                  <div v-for="d in daily" :key="d.date" class="day">
                    <div class="date">
                      {{
                        new Date(d.date).toLocaleDateString("zh-CN", {
                          month: "numeric",
                          day: "numeric",
                          weekday: "short"
                        })
                      }}
                    </div>
                    <div class="text">{{ d.text }}</div>
                    <div class="temps">
                      <b>{{ Math.round(d.tmax) }}°</b> /
                      <span>{{ Math.round(d.tmin) }}°</span>
                    </div>
                    <div class="pop">
                      💧 {{ d.pop ?? 0 }}% · {{ d.rain ?? 0 }}mm
                    </div>
                  </div>
                </transition-group>

                <el-alert
                  v-if="weatherError"
                  :title="weatherError"
                  type="warning"
                  show-icon
                  class="mt-2"
                />
              </div>
            </el-card>
          </el-col>

          <!-- 右：备忘录卡片 -->
          <el-col :xs="24" :md="12">
            <el-card shadow="hover" class="block-card notes">
              <template #header>
                <div class="block-header">
                  <span class="card-title">备忘录</span>
                </div>
              </template>

              <div class="add">
                <el-input
                  v-model="memoText"
                  placeholder="记录待办事项…"
                  clearable
                />
                <el-select
                  v-model="selectedPriority"
                  size="default"
                  class="prio"
                >
                  <el-option label="高" value="high" />
                  <el-option label="中" value="medium" />
                  <el-option label="低" value="low" />
                </el-select>
                <el-date-picker
                  v-model="selectedDueAt"
                  type="datetime"
                  placeholder="截止时间"
                  class="date"
                />
                <el-button type="primary" @click="addMemo" round
                  >添加</el-button
                >
                <el-button @click="clearCompleted" round>清除已完成</el-button>
              </div>

              <template v-if="memosView.length">
                <transition-group name="list" tag="ul" class="list">
                  <li
                    v-for="m in memosView"
                    :key="m.id"
                    :class="['memo-item', { done: m.done }, dueStatus(m)]"
                  >
                    <div class="left">
                      <label class="li-inner">
                        <el-checkbox
                          :model-value="m.done"
                          @change="() => toggleMemo(m.id)"
                        />
                        <span class="text">{{ m.text }}</span>
                        <el-tag
                          size="small"
                          :type="priorityMeta[m.priority].type"
                          effect="light"
                          round
                        >
                          {{ priorityMeta[m.priority].label }}
                        </el-tag>
                      </label>
                      <div class="meta">
                        <span class="due" :class="dueStatus(m)"
                          >⏰ {{ fmtDue(m.dueAt) }}</span
                        >
                      </div>
                    </div>

                    <div class="item-actions">
                      <el-select
                        :model-value="m.priority"
                        @update:model-value="
                          (v: any) => updatePriority(m.id, v as Priority)
                        "
                        size="small"
                        class="prio"
                      >
                        <el-option label="高" value="high" />
                        <el-option label="中" value="medium" />
                        <el-option label="低" value="low" />
                      </el-select>
                      <el-date-picker
                        :model-value="m.dueAt ? new Date(m.dueAt) : null"
                        @update:model-value="(d: any) => updateDue(m.id, d)"
                        type="datetime"
                        placeholder="截止"
                        size="small"
                        class="date"
                      />
                      <el-button text type="danger" @click="removeMemo(m.id)"
                        >删除</el-button
                      >
                    </div>
                  </li>
                </transition-group>
              </template>
              <el-empty description="还没有备忘，快来添加吧！" v-else />
            </el-card>
          </el-col>
        </el-row>
      </section>
    </el-main>

    <el-backtop :right="24" :bottom="24" />
  </el-container>
</template>

<style scoped>
.page {
  /* background: #f6f8fb; */
  color: #0f172a;
  min-height: 100svh;
}
.container {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 20px;
}

/* 顶部导航更轻薄 */
.nav {
  position: sticky;
  top: 0;
  z-index: 20;
  backdrop-filter: saturate(180%) blur(10px);
  background: rgba(255, 255, 255, 0.75);
  border-bottom: 1px solid rgba(15, 23, 42, 0.06);
}
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 56px;
}
.title {
  font-weight: 700;
  letter-spacing: 0.5px;
}

.dashboard {
  padding: 20px 0;
}
.block-card {
  border-radius: 16px;
  overflow: hidden;
}
.block-card :deep(.el-card__header) {
  padding: 10px 16px;
  background: #ffffff;
}
.block-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.card-title {
  font-weight: 600;
  letter-spacing: 0.3px;
}

/* 天气卡片视觉升级 */
.weather-card {
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.06);
}
.gradient-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-radius: 14px;
  padding: 16px 18px;
  background: linear-gradient(135deg, #e8f0ff 0%, #f7fbff 100%);
  border: 1px solid rgba(30, 64, 175, 0.08);
}
.current-left {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.big {
  font-size: 56px;
  line-height: 1;
  font-weight: 700;
  letter-spacing: -1px;
}
.location {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.city {
  font-size: 18px;
  font-weight: 600;
}
.wx-icon {
  font-size: 40px;
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.08));
}

.metrics {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  margin: 12px 0 4px;
}
.metric {
  background: #fff;
  border: 1px solid rgba(15, 23, 42, 0.06);
  border-radius: 12px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
}
.metric .label {
  font-size: 12px;
  color: #64748b;
}
.metric b {
  font-size: 16px;
}

.forecast {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  margin-top: 8px;
}
.day {
  background: #fff;
  border: 1px solid rgba(15, 23, 42, 0.06);
  border-radius: 12px;
  padding: 12px;
  transition:
    transform 0.18s ease,
    box-shadow 0.18s ease;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.03);
}
.day:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06);
}
.day .date {
  color: #64748b;
  font-size: 13px;
  margin-bottom: 6px;
}
.day .text {
  font-size: 13px;
  margin-bottom: 4px;
  color: #0f172a;
  opacity: 0.85;
}
.day .temps {
  font-weight: 700;
  margin-bottom: 4px;
}
.day .pop {
  color: #64748b;
  font-size: 12px;
}

/* 备忘录美化 */
.notes {
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.06);
}
.add {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-bottom: 10px;
  flex-wrap: wrap;
}
.add .prio {
  width: 96px;
}
.add .date {
  width: 200px;
}

.list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.memo-item {
  background: #fff;
  border: 1px solid rgba(15, 23, 42, 0.06);
  border-radius: 12px;
  padding: 10px 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  transition:
    background 0.18s ease,
    box-shadow 0.18s ease;
}
.memo-item:hover {
  background: #fafcff;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06);
}
.li-inner {
  display: flex;
  align-items: center;
  gap: 10px;
}
.left {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.meta {
  font-size: 12px;
  color: #64748b;
}
.due.soon {
  color: #d97706;
}
.due.overdue {
  color: #b91c1c;
  font-weight: 600;
}
.item-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}
.item-actions .prio {
  width: 90px;
}
.item-actions .date {
  width: 180px;
}
.done .text {
  text-decoration: line-through;
  opacity: 0.55;
}

/* 动画 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
.list-enter-active,
.list-leave-active {
  transition: all 0.18s;
}
.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateY(4px);
}

/* 自适应 */
@media (max-width: 900px) {
  .container {
    padding: 0 16px;
  }
  .forecast {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
</style>
